package com.blm.service.impl;

import com.blm.common.constants.CacheConstant;
import com.blm.common.constants.ExceptionConstant;
import com.blm.dto.StoreQueryDTO;
import com.blm.entity.Food;
import com.blm.entity.Store;
import com.blm.entity.StoreCategory;
import com.blm.exception.CommonException;
import com.blm.repository.CategoryRepository;
import com.blm.repository.FoodRepository;
import com.blm.repository.ReviewRepository;
import com.blm.repository.StoreRepository;
import com.blm.service.FoodCategoryService;
import com.blm.service.StoreService;
import com.blm.vo.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StoreServiceImpl extends BaseService implements StoreService {

    @Autowired
    private StoreRepository storeRepository;

    @Autowired
    private FoodRepository foodRepository;

    @Autowired
    private ReviewRepository reviewRepository;
    
    @Autowired @Lazy
    private StoreServiceImpl self;
    @Autowired
    private FoodCategoryService foodCategoryService;
    @Autowired
    private CategoryRepository categoryRepository;

    @Override
    @Cacheable(value = CacheConstant.STORE_LIST_USER, key = "#queryDTO")
    public PageVO<StoreVO> listStores(StoreQueryDTO queryDTO) {
        PageHelper.startPage(queryDTO.getPage(), queryDTO.getSize());

        List<Store> stores = storeRepository.findByFilters(queryDTO);
        Page<Store> pageInfo = (Page<Store>) stores;
        List<StoreVO> storeVOs = entity2VO(stores, StoreVO.class);

        return new PageVO<>(queryDTO.getPage(), queryDTO.getSize(), pageInfo.getTotal(), pageInfo.getPages(), storeVOs);
    }

    @Override
    @Cacheable(value = CacheConstant.STORE_RECOMMEND, key = "#longitude + '_' + #latitude")
    public List<StoreVO> listRecommended(Double longitude, Double latitude) {
        // todo: 根据用户位置推荐店铺
        return entity2VO(storeRepository.findFeatured(), StoreVO.class);
    }

    @Override
    @Cacheable(value = CacheConstant.STORE_DETAIL, key = "#storeId")
    public StoreDetailVO getStoreDetail(Long storeId) {
        Store store = self.getStoreById(storeId);
        StoreDetailVO vo = new StoreDetailVO();
        BeanUtils.copyProperties(store, vo);
        // 分类
        List<FoodCategoryVO> categories = foodCategoryService.getCategoriesByStoreId(storeId);
        vo.setCategories(categories);
        // 推荐商品
        List<Food> foods = foodRepository.findONFeaturedByStoreId(storeId);
        vo.setFeaturedFoods(entity2VO(foods, FoodVO.class));
        return vo;
    }

    @Override
    @Cacheable(value = CacheConstant.CATEGORIES, key = "'store'")
    public List<StoreCategoryVO> listStoreCategories() {
        List<StoreCategory> categories = categoryRepository.getStoreCategories();
        return entity2VO(categories, StoreCategoryVO.class);
    }

    @Override
    @Cacheable(value = CacheConstant.FOOD_USER, key = "#storeId + '_' + #categoryId")
    public List<FoodVO> listStoreFoods(Long storeId, Long categoryId) {
        List<Food> foods;
        if(categoryId == null){
            foods = foodRepository.findONByStoreId(storeId);
        }else{
            foods = foodRepository.findONByStoreIdAndCategoryId(storeId, categoryId);
        }

        return entity2VO(foods, FoodVO.class);
    }

    @Override
    @Cacheable(value = CacheConstant.FOOD_DETAIL, key = "#foodId")
    public FoodDetailVO getFoodDetail(Long foodId) {
        Food food = foodRepository.findONById(foodId)
                .orElseThrow(() -> new CommonException(ExceptionConstant.FOOD_NOT_FOUND));
        FoodDetailVO vo = new FoodDetailVO();
        BeanUtils.copyProperties(food, vo);

        List<ReviewVO> reviewVOs = entity2VO(reviewRepository.findByFoodId(foodId), ReviewVO.class);
        vo.setReviews(reviewVOs);
        return vo;
    }

    @Override
    public Long getStoreOwnerId(Long storeId) {
        Object ownerId = self._getStoreOwnerId(storeId);
        if (ownerId == null) {
            throw new CommonException(ExceptionConstant.STORE_NOT_FOUND);
        } else if (ownerId instanceof Integer){
            // Handle case where ownerId is returned as Integer
            return ((Integer) ownerId).longValue();
        }
        return (Long) ownerId;
    }

    /**
     * getStoreOwnerId helper method
     * do not use this method directly, use getStoreOwnerId instead
     */
    @Cacheable(value = CacheConstant.STORE_OWNER, key = "#storeId", unless = "#result == null")
    public Object _getStoreOwnerId(Long storeId) {
        return storeRepository.findOwnerIdByStoreId(storeId);
    }

    @Override
    @Cacheable(value = CacheConstant.STORE, key = "#storeId")
    public Store getStoreById(Long storeId) {
        return storeRepository.findById(storeId)
                .orElseThrow(() -> new CommonException(ExceptionConstant.STORE_NOT_FOUND));
    }

    @Override
    public void verifyStoreOwner(Long storeId, Long userId) {
        Long storeOwnerId = self.getStoreOwnerId(storeId);
        if (!storeOwnerId.equals(userId)) {
            throw new CommonException(ExceptionConstant.STORE_UNAUTHORIZED);
        }
    }
}